using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using UWBGL_WinForms_Lib1;
using UWBGL_XNA_Lib13;
using XNA_SceneNode;


// For sound - Check below for the commented out sections.

using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;


//Thanks to...
//http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series1/Keyboard.php
//For keyboard input help

namespace XNA_SceneNode
{
	public class Model
	{
		#region globals
		UWB_PrimitiveRectangle background;
		enum arrowDirection { up, down, left, right };

		Submarine Sub; // the object under user ctrl
		int fps_counter = 0;
		int fps = 0;
		float fps_timer = 0;

		public struct CONSTANTS
		{ 
			public static float SUBMARINE_SPEEDLIMIT = 8; // maximum speed (pixels per update)
			public static float WALL_WIDTH = 6; // measured in world-coord
			public static float WORLD_WIDTH = 160; // world's dimensions
			public static float WORLD_HEIGHT = 100;
		};
		
		private UWB_SceneNode LeftWall;
		private UWB_SceneNode RightWall;
		private UWB_SceneNode Floor;
		private UWB_SceneNode Celing;

		private UWB_SceneNode mActiveNode; // for SceneControl output, remove later 

		private UWB_XNADrawHelper mDrawHelper;
		private UWB_BoundingBox mWorldBounds; // bounding box representing world

		private UWB_Clock mStopWatch;

		private bool Shrink = true;

		//These were taken ouf the the update function to get it running faster
		UWB_XFormInfo XFHolder;
		Vector3 VecHold;
		KeyboardState keyState;
		UWB_SceneNode ScopeNodeHolder;
		UWB_XFormInfo ScopeXF;

		// This will animate the grab
		bool Grab;
		bool GrabOut;
		bool Grabbed;
		bool GrabComplete;
		UWB_XFormInfo ArmXF;
		Vector3 ArmVecHold;
		UWB_XFormInfo PinchTopXF;
		UWB_BoundingBox PinchTopBounds;
		//Vector3 PinchTopVec;
		UWB_XFormInfo PinchBottomXF;
		UWB_BoundingBox PinchBottomBounds;
		//Vector3 PinchBottomVec;
		float BottomRotate;
		float TopRotate;

		UWB_BoundingVolume SubBodyBound;

		// "Fish" Stuff
		int MAXFISH = 60;
		//int MAXFISH = 3;
		UWB_SceneNode FishNode;
		UWB_PrimitiveRectangle[] FishBowl;
		bool FishTest;

		//Mine Stuff
		int MAXMINES = 10;
		UWB_PrimitiveStar[] MineBowl;
		Vector3 MineLocation;
		bool Hit;

		//Score & Life
        int Score;
		int Life;
        int STARTLIFE = 6;

		// Game Over & Pause
		bool GameOver;
		bool Pause;
		int Level;


        //Sound
        // Audio objects
        AudioEngine engine;
        SoundBank soundBank;
        WaveBank waveBank;

        
		#endregion

		public Model() // constructor
		{
			GameOver = false;
			Pause = false;
			Life = STARTLIFE;
			Level = 1;
			Hit = false;

			FishTest = false;
			FishBowl = new UWB_PrimitiveRectangle[MAXFISH];

			MineBowl = new UWB_PrimitiveStar[MAXMINES];

			Sub = new Submarine("Sub");
			Sub.Center = new Vector3(10, 10, 0);
			mActiveNode = Sub;

			background = new UWB_PrimitiveRectangle();
			background.center = new Vector3(CONSTANTS.WORLD_WIDTH / 2, CONSTANTS.WORLD_HEIGHT / 2, 0);
			background.width = CONSTANTS.WORLD_WIDTH;
			background.height = CONSTANTS.WORLD_HEIGHT;
			background.enableTexturing(true);
			background.setTextureFileName("back");

			mStopWatch = new UWB_Clock(); // timer
			mWorldBounds = new UWB_BoundingBox(new Vector3(0, 0, 0), new Vector3(CONSTANTS.WORLD_WIDTH, CONSTANTS.WORLD_HEIGHT, 0)); // world size

			// use the CONSTANTS struct to set world dimensions, walls will generate from those values
			#region Walls, Floor & Celing
			// Making our world
			// Since our sub is around 12 high and 20 wide (before scaling) we can make the world 150 x 200

			//Let's make the world for our sub
			LeftWall = new UWB_SceneNode("Left Wall");
			UWB_PrimitiveList LeftWallList = new UWB_PrimitiveList();
			LeftWall.setPrimitive(LeftWallList);
			UWB_PrimitiveRectangle LWallBox = new UWB_PrimitiveRectangle();
			LWallBox.center = new Vector3(-CONSTANTS.WALL_WIDTH/2, mWorldBounds.height() / 2, 0);
			LWallBox.width = CONSTANTS.WALL_WIDTH;
			LWallBox.height = mWorldBounds.height();
			LWallBox.setFlatColor(new Color(10, 10, 9));
			LWallBox.setTextureFileName("Rock Wall Dark"); // texture
			LWallBox.enableTexturing(true);
			LWallBox.setShadeMode(eShadeMode.smFlat);
			LeftWallList.append(LWallBox);

			// Right Wall
			RightWall = new UWB_SceneNode("Right Wall");
			UWB_PrimitiveList RightWallList = new UWB_PrimitiveList();
			RightWall.setPrimitive(RightWallList);
			UWB_PrimitiveRectangle RWallBox = new UWB_PrimitiveRectangle();		
			RWallBox.center = new Vector3(mWorldBounds.width() + CONSTANTS.WALL_WIDTH/2, mWorldBounds.height() /2,0);;
			RWallBox.width = CONSTANTS.WALL_WIDTH;
			RWallBox.height = mWorldBounds.height();
			RWallBox.enableTexturing(true);
			RWallBox.setTextureFileName("Rock Wall Dark");
			RWallBox.setFlatColor(new Color(10, 10, 9));
			RWallBox.setShadeMode(eShadeMode.smFlat);
			RightWallList.append(RWallBox);

			// Floor
			Floor = new UWB_SceneNode("Floor");
			UWB_PrimitiveList FloorList = new UWB_PrimitiveList();
			Floor.setPrimitive(FloorList);
			UWB_PrimitiveRectangle FloorBox = new UWB_PrimitiveRectangle();
			FloorBox.center = new Vector3(mWorldBounds.width() / 2, -CONSTANTS.WALL_WIDTH / 2, 0);
			FloorBox.width = mWorldBounds.width() + 2 * CONSTANTS.WALL_WIDTH; // extend to L/R walls
			FloorBox.height = CONSTANTS.WALL_WIDTH;
			FloorBox.enableTexturing(true);
			FloorBox.setTextureFileName("Sandy Bottom 2");
			FloorBox.setFlatColor(new Color(10, 10, 9));
			FloorBox.setShadeMode(eShadeMode.smFlat);
			FloorList.append(FloorBox);

			// Celing
			Celing = new UWB_SceneNode("Celing");
			UWB_PrimitiveList CelingList = new UWB_PrimitiveList();
			Celing.setPrimitive(CelingList);
			UWB_PrimitiveRectangle CelingBox = new UWB_PrimitiveRectangle();
			CelingBox.center = new Vector3(mWorldBounds.width() / 2, mWorldBounds.height() + CONSTANTS.WALL_WIDTH / 2, 0);
			CelingBox.width = mWorldBounds.width() + 2 * CONSTANTS.WALL_WIDTH;
			CelingBox.height = CONSTANTS.WALL_WIDTH;
			CelingBox.setFlatColor(Color.Aquamarine);
			CelingBox.setShadeMode(eShadeMode.smFlat);
			CelingList.append(CelingBox);
			#endregion // End of making the walls

			#region Baby Fish (Scene Node Way) **DEAD**
			//// We'll make a bunch of "Baby Fish Nodes"
			//FishNode = new UWB_SceneNode("Main Fish Node");
			//String BabyFishName = "";
			//for (int qq = 0; qq < MAXFISH; qq++)
			//{
			//    BabyFishName = "Baby Fish " + qq.ToString();
			//    //make a baby fish node
			//    //Plug into FishNode
			//    FishNode.insertChildNode(new UWB_SceneNode(BabyFishName));

			//    //Now stick a shape in the child node

			//    UWB_PrimitiveRectangle FishRec = new UWB_PrimitiveRectangle();
			//    //UWB_Utility.UWB_RandomNumber(5.0f, 20.0f);
			//    FishRec.setCorners(new Vector3(7.0f, 2.0f, 0.0f), new Vector3(9.0f, 4.0f, 0.0f));
			//    FishRec.setFlatColor(new Color(1, 10, 100));

			//    FishRec.setShadeMode(eShadeMode.smFlat);

			//    FishNode.getChildNode(qq).setPrimitive(FishRec);


			//}

			#endregion

			#region Baby Fish (The Primitive Way)
			//put some squares in the fish bowl
			for (int dd = 0; dd < MAXFISH; dd++)
			{

				FishBowl[dd] = new UWB_PrimitiveRectangle();
				//float XSpot = UWB_Utility.UWB_RandomNumber(5.0f, 25.0f);
				//float YSpot = UWB_Utility.UWB_RandomNumber(5.0f, 15.0f);
				float XSpot = UWB_Utility.UWB_RandomNumber(5.0f, 140.0f);
				float YSpot = UWB_Utility.UWB_RandomNumber(5.0f, 90.0f);
				FishBowl[dd].setCorners(new Vector3(XSpot, YSpot, 0.0f), new Vector3(XSpot + 4, YSpot + 2, 0.0f));
				FishBowl[dd].setFlatColor(new Color(1, 1, 100));
				FishBowl[dd].setFillMode(eFillMode.fmSolid);
                // Fish texture
                FishBowl[dd].setTextureFileName("Fish+Jewel"); // texture
                FishBowl[dd].enableTexturing(true);
				FishBowl[dd].enableBlending(true);
				FishBowl[dd].setShadeMode(eShadeMode.smFlat);
				FishBowl[dd].setVelocity(new Vector3(2f, 0.3f, 0));
			}



			#endregion

			#region Mines (The bad guys)

			//Make a bunch of mines
			for (int mm = 0; mm < MAXMINES; mm++)
			{

				MineBowl[mm] = new UWB_PrimitiveStar();
				//float XSpot = UWB_Utility.UWB_RandomNumber(5.0f, 25.0f);
				//float YSpot = UWB_Utility.UWB_RandomNumber(5.0f, 15.0f);
				float XSpot = UWB_Utility.UWB_RandomNumber(5.0f, 140.0f);
				float YSpot = UWB_Utility.UWB_RandomNumber(140.0f, 150.0f);

				//This will put the Mines randomly on X and way up high in Y
				MineBowl[mm].setCenter(new Vector3(XSpot, YSpot, 0));
				MineBowl[mm].setRadius(2);
				MineBowl[mm].setShadeMode(eShadeMode.smFlat);
				MineBowl[mm].setFlatColor(new Color(3, 3, 3));

				// This is probably where we will texture them, if we want
			}
			#endregion

			//Set our gabber to false
			Grab = false;
			GrabOut = false;
			GrabComplete = false;

			mDrawHelper = new UWB_XNADrawHelper();

			// Initialize audio objects.
			//*****************************************************
			//engine = new AudioEngine("Content\\Audio\\PlaySound.xgs");
			//soundBank = new SoundBank(engine, "Content\\Audio\\Sound Bank.xsb");
			//waveBank = new WaveBank(engine, "Content\\Audio\\Wave Bank.xwb");

		}

		public void updateSimulation()
		{
			//Get the keyboard state
			keyState = Keyboard.GetState();

			//Check if the Game is over, or it's paused
			if (GameOver || Pause)
			{
				// Then all we have to check is unpause
				//Pause or Unpause
				if (keyState.IsKeyDown(Keys.P))
				{
					Pause = !Pause;
				}
			}
			else
			{
				#region Inside Update Simulation
				float elapsed_seconds = mStopWatch.getSecondsElapsed();

				for (int dd = 0; dd < MAXFISH; dd++)
				{

					FishBowl[dd].update(elapsed_seconds);
				}

                #region Reset (When R is pressed)
                //if you hit R it will reset the game
                if (keyState.IsKeyDown(Keys.R))
                {
                    // First off move the sub back to the spot
					Sub.Center = new Vector3(10, 10, 0);

                    //Then randomly reset the fish
                    for (int NumFish = 0; NumFish < MAXFISH; NumFish++)
                    {
                        float XSpot = UWB_Utility.UWB_RandomNumber(10, CONSTANTS.WORLD_WIDTH-10);
                        float YSpot = UWB_Utility.UWB_RandomNumber(10, CONSTANTS.WORLD_HEIGHT-10);
                        FishBowl[NumFish].setCorners(new Vector3(XSpot, YSpot, 0.0f), new Vector3(XSpot + 4, YSpot + 2, 0.0f));
                    }
                    //Then Randomly reset the mines
                    for (int NumMines = 0; NumMines < MAXMINES; NumMines++)
                    {
						float XSpot = UWB_Utility.UWB_RandomNumber(10, CONSTANTS.WORLD_WIDTH-10);
						float YSpot = UWB_Utility.UWB_RandomNumber(CONSTANTS.WORLD_HEIGHT, CONSTANTS.WORLD_HEIGHT+10);
                        MineBowl[NumMines].setCenter(new Vector3(XSpot,YSpot,0));
                    }

                    //Then rest life
                    Life = STARTLIFE;
                    Level = 1;
                    Score = 0;
                }
                #endregion

                #region fps counter
                if (fps_timer >= 1)
				{
					fps = fps_counter;
					fps_counter = 0;
					fps_timer = 0;
				}
				else
				{
					fps_timer += elapsed_seconds;
					++fps_counter;
				}
				#endregion

				#region moving with arrow keys
				// How are we moving?
				int Right = 0; // -1 = left. 0 = no x movement. 1 = right
				int Up = 0; // -1 = up. 0 = no y movement. 1 = down
				bool Moving = false;

				//Get the keyboard state
				//keyState = Keyboard.GetState();

				if (keyState.IsKeyDown(Keys.P))
				{
					Pause = !Pause;
				}

				//Up and down movement
				if (keyState.IsKeyDown(Keys.Down))
					go(arrowDirection.down);
				else
					if (keyState.IsKeyDown(Keys.Up))
						go(arrowDirection.up);
					else
						Up = 0;

				// Left and right movement
				if (keyState.IsKeyDown(Keys.Right))
					go(arrowDirection.right);
				else
					if (keyState.IsKeyDown(Keys.Left))
						go(arrowDirection.left);
					else
						Right = 0;

				//Sub.setVelocity(new Vector3(1f, 0, 0));


				//Check for moving of the wheel
				if ((Right != 0) || (Up != 0))
				{
					Moving = true;
				}
				#endregion

				#region Wall Bumping
				//Let's check for the wall bumping
				//Left wall
				if (LeftWall.getBounds(mDrawHelper, false).intersects(Sub.getBounds(mDrawHelper, false)))
				{
					//we hit the left wall, push the sub right

					//get the newest location of the sub
					XFHolder = Sub.getXFormInfo();
					VecHold = XFHolder.getTranslation();
					//Then push it righ
					VecHold.X += 1;

					//Update it
					XFHolder.setTranslation(VecHold);
					Vector3 origVelocity = Sub.getVelocity();
					Sub.setVelocity(new Vector3(0.1f, origVelocity.Y, 0));
				}

				//Right wall
				if (RightWall.getBounds(mDrawHelper, false).intersects(Sub.getBounds(mDrawHelper, false)))
				{
					//we hit the left wall, push the sub right

					//get the newest location of the sub
					XFHolder = Sub.getXFormInfo();
					VecHold = XFHolder.getTranslation();
					//Then push it left (a little bit more than the other wall for the arm)
					VecHold.X -= 0.1f;

					//Update it
					XFHolder.setTranslation(VecHold);
					Vector3 origVelocity = Sub.getVelocity();
					Sub.setVelocity(new Vector3(-0.1f, origVelocity.Y, 0));
				}

				//Floor
				if (Floor.getBounds(mDrawHelper, false).intersects(Sub.getBounds(mDrawHelper, false)))
				{
					//we hit the left wall, push the sub right
					
					//get the newest location of the sub
					XFHolder = Sub.getXFormInfo();
					VecHold = XFHolder.getTranslation();
					//Then push it up a little
					VecHold.Y += 0.1f;

					//Update it
					XFHolder.setTranslation(VecHold);

					Vector3 origVelocity = Sub.getVelocity();
					Sub.setVelocity(new Vector3(origVelocity.X, 0.1f, 0));
				}
				//Celing
				if (Celing.getBounds(mDrawHelper, false).intersects(Sub.getBounds(mDrawHelper, false)))
				{
					//we hit the left wall, push the sub right

					//get the newest location of the sub
					XFHolder = Sub.getXFormInfo();
					VecHold = XFHolder.getTranslation();
					//Then push it Down a little more than floor
					VecHold.Y -= 0.1f;

					//Update it
					XFHolder.setTranslation(VecHold);

					Vector3 origVelocity = Sub.getVelocity();
					Sub.setVelocity(new Vector3(origVelocity.X, -0.1f, 0));
				}
				#endregion

				#region Grab Animation
				//Let's animate the grabber if we need to
				if (keyState.IsKeyDown(Keys.F))
				{
					// space is pressed, animate the claw
					Grab = true;
					GrabComplete = false;
				}

				if (Grab)
				{
					if (GrabOut)
					{
						//move the pinchers
						PinchBottomXF = Sub.getPincherBottomNode().getXFormInfo();
						BottomRotate = PinchBottomXF.getRotationInDegrees();
						//then add a little to it
						if (BottomRotate < 45.0f)
						{
							//add a little bit to it
							BottomRotate += 5.0f;
							//update it
							PinchBottomXF.setRotationDegrees(BottomRotate);
						}

						//move the pinchers
						PinchTopXF = Sub.getPincherTopNode().getXFormInfo();
						TopRotate = PinchTopXF.getRotationInDegrees();
						//then add a little to it
						if (TopRotate > -45.0f)
						{
							//add a little bit to it
							TopRotate -= 5.0f;
							//update it
							PinchTopXF.setRotationDegrees(TopRotate);
						}

						//Check to see if we've completely grabbed
						if ((TopRotate <= -45) && (BottomRotate >= 45))
						{
							// we have grabbed
							Grabbed = true;
						}

						//Check to see if we need to pull back
						if (Grabbed)
						{
							//pull it back in and reset things
							ArmXF = Sub.getArmNode().getXFormInfo();
							ArmVecHold = ArmXF.getScale();
							if (ArmVecHold.X > 0.2f)
							{
								//Bump it down
								ArmVecHold.X -= 0.1f;
								//ArmVecHold.Y = 1.0f;
								// Update it
								ArmXF.setScale(ArmVecHold);

							}
							else
							{
								//we have fully completed a grab
								GrabComplete = true;
							}

							////Warp it back now as a test
							//ArmVecHold.X = 0.1f;
							//ArmXF.setScale(ArmVecHold);


						}
						if (GrabComplete)
						{
							//set grab to false
							Grab = false;
							Grabbed = false;
							GrabOut = false;
							//Reset the rotations of the arms
							PinchTopXF.setRotationDegrees(0.0f);
							TopRotate = 0.0f;
							PinchBottomXF.setRotationDegrees(0.0f);
							BottomRotate = 0.0f;
						}
					}
					else
					{
						//if we are to grab then extend the arm
						ArmXF = Sub.getArmNode().getXFormInfo();
						ArmVecHold = ArmXF.getScale();
						//bump it up a little
						if (ArmVecHold.X <= 1)
						{
							//Bump it up
							ArmVecHold.X += 0.1f;
							// Update it
							ArmXF.setScale(ArmVecHold);
						}
						else
						{
							//The arm is fully out, next step
							GrabOut = true;
						}
					}//else if the grabb is not fully out
				}//if we are grabbing
				#endregion

                #region Bumping into fish
                //get Bounding Volumes
				//UWB_BoundingBox PinchTopVol = Sub.getPincherTopNode().getBounds(mDrawHelper, false);
				//Sub.getPincherTopNode().getPrimitive().getBoundingVolume(mDrawHelper.getLod());
				//UWB_BoundingVolume PinchBottomVol = Sub.getPincherBottomNode().getPrimitive().getBoundingVolume(mDrawHelper.getLod());
				UWB_BoundingVolume FishVol = new UWB_BoundingVolume();


				//Check for all the hits
				for (int ff = 0; ff < MAXFISH; ff++)
				{
					FishVol = FishBowl[ff].getBoundingVolume(mDrawHelper.getLod());

					// ** I HAVE TRYED THIS SO MANY TIMES.
					//  For now let's make it collison with the body

					if (Sub.getBounds(mDrawHelper, false).intersects(FishVol))
					{
						//Make the fish go far away
						FishBowl[ff].moveTo(-100.0f, -100.0f);

						//Make the score go up
						Score++;

                        // Play the sound.
                        //************************************************
                        //Cue cue = soundBank.GetCue("PickUpNoise");
                        //cue.Play();

						if (Score >= (MAXFISH / 2))
						{
							//Bump it up to level 2
							Level++;
						}
						if (Score >= ((MAXFISH / 4) * 3))
						{
							//Bump it up to level 3
							Level++;
						}
					}//End of fish bump check

					//Are we above level 1?
					if (Level > 1)
					{
						//then check for mine collion
						for (int mm = 0; mm < MAXMINES; mm++)
						{

							//if(SubBodyBound.intersects(MineBowl[mm].getBoundingVolume(mDrawHelper.getLod())))
							if (Sub.getBounds(mDrawHelper, false).intersects(MineBowl[mm].getBoundingVolume(mDrawHelper.getLod())))
							{
								// Decrease your life
								Hit = true;

								//Move the mine way up
								MineLocation = MineBowl[mm].getLocation();
								MineLocation.Y = 155;
								MineBowl[mm].setCenter(MineLocation);

								Sub.bobbingSubmarine();
							}

							//if(Life<=0)
							//{
							//    GameOver = true;
							//}
						}
					}

					#region Other ways to try and get fish grabbing

					//if (PinchTopVol.intersects(FishVol))
					//{
					//    //Pause = true;
					//}
					////if (Sub.getBounds(mDrawHelper, false).intersects(FishVol))
					////{
					////    GameOver = true;
					////}

					////Sub -> Child 2 -> Child 0 -> Child 0 is the top pincher
					////Sub -> Child 2 -> Child 0 -> Child 1 is the bottom pincher

					////Sub.getChildNode(2).getChildNode(0).getChildNode(0).setPivotVisible(true);
					////if (Sub.getPincherTopNode().getBounds(mDrawHelper, false).intersects(FishVol))
					//Sub.getChildNode(2).getChildNode(0).setPivotVisible(true);
					//if(Sub.getChildNode(2).getBounds(mDrawHelper,false).intersects(FishVol))
					//{
					//    Pause = true;
					//}
					#endregion

				}// End of bumping the fish
                #endregion

                #region Scope Animation
                //Animate the scope all the time

				//Get the sub current location
				ScopeNodeHolder = Sub.getScopeNode();
				ScopeXF = ScopeNodeHolder.getXFormInfo();
				Vector3 ScopeScale = ScopeXF.getScale();
				if (Shrink)
				{
					ScopeScale.X -= 0.1f;
					if (ScopeScale.X <= -1)
					{
						Shrink = false;
					}
				}
				else
				{
					ScopeScale.X += 0.1f;
					if (ScopeScale.X >= 1)
					{
						Shrink = true;
					}
				}

				//Then update
				ScopeXF.setScale(ScopeScale);
                #endregion

                #region Moving The Mines
                //Move all the mines
				if (Level > 1)
				{
					for (int WhatMine = 0; WhatMine < MAXMINES; WhatMine++)
					{
						MineLocation = MineBowl[WhatMine].getLocation();
						MineLocation.Y -= (0.5f * Level);
						if (MineLocation.Y < -5)
						{
							MineLocation.Y = UWB_Utility.UWB_RandomNumber(150.0f, 170.0f); ;
						}
						MineBowl[WhatMine].setCenter(MineLocation);
					}
				}


				#endregion

				// actions on submarine
				Sub.rotateWheelDegree(10);
				Sub.flipVelocity();
				Sub.moveNodeByVelocity(elapsed_seconds);
				Sub.bobbingSubmarine();

				#endregion
			} // end of if we need to update

			//At the very end check life
			if (Hit)
			{

                // Play the sound.
                //************************************************
                //Cue cue = soundBank.GetCue("Bubbles");
                //cue.Play();

				//Decrease Life
				Life--;

                //************************************
                // Lower the health bar

				if (Life <= 0)
				{
					GameOver = true;
				}

				Hit = false;
			}// end of if we were hit by a bad guy

            // This would be a good spot to update any text boxes
            // Level
            // Score
            // Life
            // Fish Left
            if (Score == MAXFISH)
            {
                // You got them all
                // Game over
                // Tell them you win
            }
		} // end of Update Simulation

		// update velocity based on direction given
		private void go(arrowDirection direction)
		{
			Vector3 inputDirection;
			switch (direction)
			{
				case arrowDirection.up:
					inputDirection = new Vector3(0, 1, 0);
					break;
				case arrowDirection.down:
					inputDirection = new Vector3(0, -1, 0);
					break;
				case arrowDirection.left:
					inputDirection = new Vector3(-1, 0, 0);
					break;
				default:
					inputDirection = new Vector3(1, 0, 0);
					break;
			}
			inputDirection *= 0.2f;

			Vector3 updatedVelocity = Sub.getVelocity() + inputDirection;
			if (updatedVelocity.Length() < CONSTANTS.SUBMARINE_SPEEDLIMIT)
				Sub.setVelocity(updatedVelocity);
			else // speed-limit breached -- set to speed limit
			{
				updatedVelocity.Normalize();
				updatedVelocity *= CONSTANTS.SUBMARINE_SPEEDLIMIT;
				Sub.setVelocity(updatedVelocity);
			}
		}

		// draw routine
		public void drawModel()
		{
			background.draw(eLevelofDetail.lodHigh, mDrawHelper);
			mDrawHelper.initializeModelTransform();

			mDrawHelper.pushModelTransform();

			eLevelofDetail lod = mDrawHelper.getLod();

			
			//drawGrid(mDrawHelper, mWorldBounds);

			Sub.draw(lod, mDrawHelper);
			//Sub.getBounds(mDrawHelper, false).draw(mDrawHelper);

			// Draw the walls
			//WorldNode.draw(lod, mDrawHelper);
			LeftWall.draw(lod, mDrawHelper);
			RightWall.draw(lod, mDrawHelper);
			//Draw the floor
			Floor.draw(lod, mDrawHelper);
			//Draw the celing
			Celing.draw(lod, mDrawHelper);

			//Then Draw the fish
			for (int rr = 0; rr < MAXFISH; rr++)
			{
				FishBowl[rr].draw(lod, mDrawHelper);
			}

			//Then draw the mines
			for (int rr = 0; rr < MAXMINES; rr++)
			{
				MineBowl[rr].draw(lod, mDrawHelper);
			}

			mDrawHelper.popModelTransform();
		}

		// function that generates a bunch of grids
		public void drawGrid(UWB_DrawHelper drawHelper, UWB_BoundingBox bounds)
		{
			// colors of axis and grid
			Color gridColor = Color.Blue;
			Color axisColor = Color.Black;

			// spacing in X and Y direction
			int separationX = 5;
			int separationY = 5;

			drawHelper.setColor1(gridColor);
			drawHelper.setColor1(gridColor);

			Vector3 minPoint = bounds.getMin();
			Vector3 maxPoint = bounds.getMax();

			float y = minPoint.Y;
			while (y < maxPoint.Y)
			{
				if (y == 0)
				{
					drawHelper.setColor1(axisColor);
					drawHelper.setColor2(axisColor);
					drawHelper.drawLine(new Vector3(minPoint.X, y, 0), new Vector3(maxPoint.X, y, 0));
					drawHelper.setColor1(gridColor);
					drawHelper.setColor2(gridColor);
				}
				else
				{
					drawHelper.setColor1(gridColor);
					drawHelper.setColor2(gridColor);
					drawHelper.drawLine(new Vector3(minPoint.X, y, 0), new Vector3(maxPoint.X, y, 0));
				}
				y += separationY;
			}

			float x = minPoint.X;
			while (x < maxPoint.X)
			{
				if (x == 0)
				{
					drawHelper.setColor1(axisColor);
					drawHelper.setColor2(axisColor);
					drawHelper.drawLine(new Vector3(x, minPoint.Y, 0), new Vector3(x, maxPoint.Y, 0));
					drawHelper.setColor1(gridColor);
					drawHelper.setColor2(gridColor);
				}
				else
				{
					drawHelper.setColor1(gridColor);
					drawHelper.setColor2(gridColor);
					drawHelper.drawLine(new Vector3(x, minPoint.Y, 0), new Vector3(x, maxPoint.Y, 0));
				}
				x += separationX;
			}
		}

		// obtain new direction for velocity
		public void setSubmarineVelocityDirection(float mouseDownX, float mouseDownY)
		{
			Vector3 originalVelocity = Sub.getVelocity();
			float originalSpeed = originalVelocity.Length();
			Vector3 mouseDownLocation = new Vector3(mouseDownX, mouseDownY, 0);
			Vector3 centerOfSub = Sub.Center;

			Vector3 newVelocity = (mouseDownLocation - centerOfSub);
			newVelocity.Normalize();

			if (originalSpeed == 0)
				originalSpeed = 0.1f;

			newVelocity *= originalSpeed;

			Sub.setVelocity(newVelocity);
		}

		// keeps direction the same as before
		public void increaseSubmarineSpeed()
		{
			Vector3 subVelocity = Sub.getVelocity();

			if (subVelocity.Length() < CONSTANTS.SUBMARINE_SPEEDLIMIT)
				Sub.setVelocity(subVelocity * 1.2f);
			else // speed-limit breached
			{
				subVelocity.Normalize();
				subVelocity *= CONSTANTS.SUBMARINE_SPEEDLIMIT;
				Sub.setVelocity(subVelocity);
			}
		}

		#region get and set
		public int FPS // frames per second
		{
			get { return fps; }
		}

		public UWB_BoundingBox getWorldBound()
		{
			return mWorldBounds;
		}

		public void setActiveNode(UWB_SceneNode n)
		{
			mActiveNode = n;
		}

		public UWB_SceneNode getActiveNode()
		{
			return mActiveNode;
		}

		public UWB_DrawHelper getDrawHelper()
		{
			return mDrawHelper;
		}

		// returns, as reference, the dimensions of the world box
		public void getWorldBounds(ref float width, ref float height)
		{
			width = mWorldBounds.width();
			height = mWorldBounds.height();
		}

		// returns bounding box representing the world
		public UWB_BoundingBox getWorldBounds()
		{
			return mWorldBounds;
		}

		public UWB_SceneNode GetRootNode()
		{
			return Sub;
		}

		// moves (translate matrix) submarine to a X,Y world coordinate
		public void setTranslation(float worldCoorX, float worldCoorY)
		{
			Sub.getXFormInfo().setTranslation(new Vector3(worldCoorX, worldCoorY, 0));
		}

		public Submarine getSubmarine()
		{
			return Sub;
		}

		public void pauseButtonPressed()
		{
			Pause = !Pause;
		}


		#endregion
	}
}

